//! GPIO interrupt handling

use super::{RK3588Gpio, regs};

/// GPIO interrupt handler trait
pub trait GpioIrqHandler {
    /// Handle a GPIO interrupt
    fn handle_irq(&self, pin: u8);
}

impl RK3588Gpio {
    /// Handle GPIO interrupts
    ///
    /// Call this from within the IRQ handler
    pub fn handle_interrupt<H: GpioIrqHandler>(&self, handler: &H) {
        let status = self.get_interrupt_status();

        // Iterate over all pins and service any pending interrupts
        for pin in 0..32 {
            if status & (1 << pin) != 0 {
                handler.handle_irq(pin);
                self.clear_interrupt(pin);
            }
        }
    }

    /// Configure debounce
    ///
    /// # Parameters
    /// - `pin`: Pin index (0-31)
    /// - `enable`: Whether to enable debounce
    ///
    /// # Notes
    /// When debounce is enabled, the input signal must stay stable for at least
    /// two debounce clock cycles before it is considered valid.
    pub fn set_debounce(&self, pin: u8, enable: bool) {
        if pin >= 32 {
            return;
        }

        let (offset, bit_index) = if pin < 16 {
            (regs::offset::DEBOUNCE_L, pin)
        } else {
            (regs::offset::DEBOUNCE_H, pin - 16)
        };

        self.write_with_mask(offset, bit_index, enable);
    }

    /// Configure the debounce clock divider
    ///
    /// # Parameters
    /// - `divider`: Division factor (0-16777215, actual division = divider + 1)
    ///
    /// # Notes
    /// Debounce clock frequency = dbclk / (divider + 1)
    pub fn set_debounce_divider(&self, divider: u32) {
        debug_assert!(divider <= 0xFFFFFF, "Divider must be 24-bit");
        self.write_reg(regs::offset::DBCLK_DIV_CON, divider & 0xFFFFFF);
    }

    /// Enable the per-pin debounce clock divider
    ///
    /// # Parameters
    /// - `pin`: Pin index (0-31)
    /// - `enable`: Whether to use the divided clock (false = raw dbclk, true = divided clock)
    pub fn set_debounce_clk_div_enable(&self, pin: u8, enable: bool) {
        if pin >= 32 {
            return;
        }

        let (offset, bit_index) = if pin < 16 {
            (regs::offset::DBCLK_DIV_EN_L, pin)
        } else {
            (regs::offset::DBCLK_DIV_EN_H, pin - 16)
        };

        self.write_with_mask(offset, bit_index, enable);
    }
}
